﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using PandemiaAdmin.Soporte;
using PandemiaAdmin.Funcionalidad;
using PandemiaAdmin.Entidades;

namespace PandemiaAdminNet.Conexiones
{
    public partial class FrmNodo : Form
    {
        #region Inicialización

        private Nodo _nodo;
        private Servidor _servidor;

        public FrmNodo(Nodo nodo, Servidor servidor)
        {
            InitializeComponent();
            _nodo = nodo;
            _servidor = servidor;
            _transferencias = new Dictionary<int, BackgroundWorker>();
            _idTransferencia = 0;
        }

        private void FrmNodo_Load(object sender, EventArgs e)
        {
            lblEstadoNodo.Text = string.Empty;
            flpTransferencias.Controls.Clear();
            Text = string.Format(@"Nodo: Alias {0} - PC: {1} - IP: {2} - ID: {3}", _nodo.Alias, _nodo.NombreMaquina, _nodo.Ip, _nodo.ID);
            EnviarAccion(TipoComando.SolicitarDrives);
        }

        #endregion

        #region Procesador

        private void bgwProcesarNodo_DoWork(object sender, DoWorkEventArgs e)
        {
            switch (_accionActual)
            {
                default:
                    EnviarAccion(e);
                    break;
            }
        }

        private void bgwProcesarNodo_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            tspEstadoNodo.Value = e.ProgressPercentage;
            lblEstadoNodo.Text = e.UserState.ToString();
        }

        private void bgwProcesarNodo_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            tvNavegador.Enabled = btnRecargarNavegador.Enabled = true;
            tspEstadoNodo.Value = 100;

            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            ResultadoComando resultado = e.Result as ResultadoComando;

            if(resultado != null && resultado.Error != null && resultado.Error.Length > 0)
            {
                MessageBox.Show(resultado.Error, "ERROR REMOTO", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (e.Cancelled)
            {
                lblEstadoNodo.Text = "Cancelado";
                return;
            }
            
            switch (_accionActual)
            {
                case TipoComando.SolicitarDrives:
                    SolicitarDrives(e);
                    break;

                case TipoComando.Explorar:
                    Explorar(e);
                    break;

                case TipoComando.Eliminar:
                    tvNavegador.SelectedNode = tvNavegador.SelectedNode.Parent;
                    EnviarAccion(TipoComando.Explorar);
                    break;

                case TipoComando.Copiar:
                    EnviarAccion(TipoComando.Explorar);
                    break;

                case TipoComando.Informar:
                    Informar(e);
                    break;

                default:
                    EnviarAccion(e);
                    break;
            }
        }

        #endregion

        #region Navegador

        private string _pathParaCopiar;
        private TipoComando _accionActual;
        private string _argumentoEjecucion;

        private string ObtenerPathSeleccionado()
        {
            string path = tvNavegador.SelectedNode.FullPath.Replace(@"\\", @"\");
            TreeNode equipo = tvNavegador.Nodes[0];

            switch (_accionActual)
            {
                case TipoComando.Copiar:
                    path = _pathParaCopiar + "|" + path;
                    break;

                case TipoComando.Ejecutar:
                    path += "|" + _argumentoEjecucion;
                    break;

                default:
                    break;
            }

            return path.Replace(equipo.Text + @"\", "");
        }

        private void EnviarAccion(TipoComando accion)
        {
            _accionActual = accion;

            string pathSeleccionado = (accion == TipoComando.SolicitarDrives) ? null : ObtenerPathSeleccionado();
            tvNavegador.Enabled = btnRecargarNavegador.Enabled = false;
            tspEstadoNodo.Value = 0;
            lblEstadoNodo.Text = "Solicitando " + _accionActual.ToString() + " " + pathSeleccionado;
            bgwProcesarNodo.RunWorkerAsync(pathSeleccionado);
        }

        private void EnviarAccion(DoWorkEventArgs e)
        {
            AdminNodos admin = new AdminNodos(_servidor);
            string path = (e.Argument == null) ? null : e.Argument.ToString();
            int idComando = admin.SolicitarAccion(_nodo, _accionActual, path);
            ResultadoComando resultado = null;

            do
            {
                resultado = admin.ObtenerResultado(idComando);
                System.Threading.Thread.Sleep(1000);
            } while (!e.Cancel && resultado == null);

            bgwProcesarNodo.ReportProgress(30, _accionActual.ToString() + " finalizada");
            e.Result = resultado;
        }

        private void EnviarAccion(RunWorkerCompletedEventArgs e)
        {
            lblEstadoNodo.Text = _accionActual.ToString() + " procesada con éxito";
        }

        private void SolicitarDrives(RunWorkerCompletedEventArgs e)
        {
            tvNavegador.Nodes.Clear();

            TreeNode equipo = new TreeNode(_nodo.NombreMaquina);
            ResultadoComando resultado = e.Result as ResultadoComando;

            if (resultado != null && resultado.Carpetas != null)
                foreach (string drive in resultado.Carpetas)
                {
                    TreeNode nodeDrive = new TreeNode(drive);
                    nodeDrive.ImageIndex = nodeDrive.SelectedImageIndex = 1;
                    nodeDrive.ContextMenuStrip = mnuOpciones;
                    equipo.Nodes.Add(nodeDrive);
                }

            tvNavegador.Nodes.Add(equipo);
        }

        private void Explorar(RunWorkerCompletedEventArgs e)
        {
            ResultadoComando resultado = e.Result as ResultadoComando;

            if (resultado == null)
                return;

            tvNavegador.SelectedNode.Nodes.Clear();

            if (resultado.Carpetas != null)
                foreach (string carpeta in resultado.Carpetas.OrderBy(c => c).ToList())
                {
                    TreeNode nodeCarpeta = new TreeNode(carpeta);
                    nodeCarpeta.ImageIndex = nodeCarpeta.SelectedImageIndex = 2;
                    nodeCarpeta.ContextMenuStrip = mnuOpciones;
                    tvNavegador.SelectedNode.Nodes.Add(nodeCarpeta);
                }


            if (resultado.Archivos != null)
                foreach (string archivo in resultado.Archivos.OrderBy(a => a).ToList())
                {
                    TreeNode nodeArchivo = new TreeNode(archivo);
                    nodeArchivo.ImageIndex = nodeArchivo.SelectedImageIndex = 3;
                    nodeArchivo.ContextMenuStrip = mnuOpciones;
                    tvNavegador.SelectedNode.Nodes.Add(nodeArchivo);
                }

            tvNavegador.SelectedNode.Expand();
        }

        private void Informar(RunWorkerCompletedEventArgs e)
        {
            ResultadoComando resultado = e.Result as ResultadoComando;

            if (resultado == null)
                return;

            FrmInforme frmInforme = new FrmInforme(resultado);
            frmInforme.MdiParent = this.MdiParent;
            frmInforme.StartPosition = FormStartPosition.CenterScreen;
            frmInforme.Show();
        }

        
        private void btnRecargarNavegador_Click(object sender, EventArgs e)
        {
            EnviarAccion(TipoComando.SolicitarDrives);
        }

        private void tvNavegador_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            tvNavegador.SelectedNode = e.Node;
        }

        private void tvNavegador_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (tvNavegador.SelectedNode.ImageIndex == 1 || tvNavegador.SelectedNode.ImageIndex == 2)
                EnviarAccion(TipoComando.Explorar);
        }

        private void tvNavegador_BeforeSelect(object sender, TreeViewCancelEventArgs e)
        {
            switch (e.Node.ImageIndex)
            {
                case 1://Drive
                    btnExplorar.Enabled = btnSubir.Enabled = true;
                    btnInformeElemento.Enabled = btnEjecutar.Enabled = btnCopiar.Enabled = btnDescargar.Enabled = btnEliminar.Enabled = false;
                    btnCopiar.Enabled = _pathParaCopiar == null;
                    btnPegar.Enabled = _pathParaCopiar != null;
                    break;

                case 2: //Carpeta
                    btnInformeElemento.Enabled = btnExplorar.Enabled = btnSubir.Enabled = btnEliminar.Enabled = true;
                    btnEjecutar.Enabled = btnCopiar.Enabled = btnDescargar.Enabled = false;
                    btnPegar.Enabled = _pathParaCopiar != null;
                    break;

                case 3: //Archivo
                    btnInformeElemento.Enabled = btnCopiar.Enabled = btnEjecutar.Enabled = btnDescargar.Enabled = btnEliminar.Enabled = true;
                    btnPegar.Enabled = btnExplorar.Enabled = btnSubir.Enabled = false;
                    break;

                default:
                    btnInformeElemento.Enabled = btnExplorar.Enabled = btnEjecutar.Enabled = btnCopiar.Enabled = btnPegar.Enabled = btnEliminar.Enabled = btnDescargar.Enabled = btnSubir.Enabled = false;
                    break;
            }

            explorarToolStripMenuItem.Enabled = btnExplorar.Enabled;
            ejecutarToolStripMenuItem.Enabled = btnEjecutar.Enabled;
            copiarToolStripMenuItem.Enabled = btnCopiar.Enabled;
            pegarToolStripMenuItem.Enabled = btnPegar.Enabled;
            eliminarToolStripMenuItem.Enabled = btnEliminar.Enabled;
            descargarToolStripMenuItem.Enabled = btnDescargar.Enabled;
            subirToolStripMenuItem.Enabled = btnSubir.Enabled;
            informarToolStripMenuItem1.Enabled = btnInformeElemento.Enabled;
        }

        private void btnExplorar_Click(object sender, EventArgs e)
        {
            EnviarAccion(TipoComando.Explorar);
        }

        private void btnEjecutar_Click(object sender, EventArgs e)
        {
            FrmEjecucion frmEjecution = new FrmEjecucion(ObtenerPathSeleccionado());
            frmEjecution.StartPosition = FormStartPosition.CenterScreen;

            if (frmEjecution.ShowDialog() == DialogResult.OK)
            {
                _argumentoEjecucion = frmEjecution.Argumentos;
                EnviarAccion(TipoComando.Ejecutar);
            }
        }

        private void btnCopiar_Click(object sender, EventArgs e)
        {
            _pathParaCopiar = ObtenerPathSeleccionado();
            lblEstadoNodo.Text = "Copiando " + _pathParaCopiar;
        }

        private void btnPegar_Click(object sender, EventArgs e)
        {
            EnviarAccion(TipoComando.Copiar);
        }

        private void btnEliminar_Click(object sender, EventArgs e)
        {
            if(MessageBox.Show("¿Eliminar " + ObtenerPathSeleccionado() + "?", "Pregunta", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                EnviarAccion(TipoComando.Eliminar);
        }

        private void btnInformeElemento_Click(object sender, EventArgs e)
        {
            EnviarAccion(TipoComando.Informar);
        }

        #endregion

        #region Transferencia

        private Dictionary<int, BackgroundWorker> _transferencias;
        private int _idTransferencia;


        private void AgregarTransferencia(bool subir)
        {
            TransferenciaItem data = new TransferenciaItem();
            data.PathRemoto = ObtenerPathSeleccionado();
            data.ArchivoLocal = ofdSubir.FileName;
            data.EsSubida = subir;
            _idTransferencia++;

            BackgroundWorker bgwTransferencia = new BackgroundWorker();
            bgwTransferencia.WorkerSupportsCancellation = true;
            bgwTransferencia.WorkerReportsProgress = true;
            bgwTransferencia.DoWork += new DoWorkEventHandler(bgwTransferencia_DoWork);
            bgwTransferencia.ProgressChanged += new ProgressChangedEventHandler(bgwTransferencia_ProgressChanged);
            bgwTransferencia.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwTransferencia_RunWorkerCompleted);
            
            _transferencias.Add(_idTransferencia, bgwTransferencia);

            Panel pnlTransferencia = new Panel();
            pnlTransferencia.Size = new Size(483, 65);
            flpTransferencias.Controls.Add(pnlTransferencia);

            Label lblDescriptionTransferencia = new Label();
            lblDescriptionTransferencia.Text = ((subir) ? "Subiendo " : "Descargando ") + data.ArchivoLocal;
            lblDescriptionTransferencia.Location = new Point(5, 10);
            lblDescriptionTransferencia.Size = new Size(441, 15);
            data.LblDescripcionTransferencia = lblDescriptionTransferencia;
            pnlTransferencia.Controls.Add(lblDescriptionTransferencia);

            ProgressBar pbEstadoTransferencia = new ProgressBar();
            pbEstadoTransferencia.Size = new Size(441, 30);
            pbEstadoTransferencia.Location = new Point(5,25);
            pnlTransferencia.Controls.Add(pbEstadoTransferencia);
            data.ProgressBar = pbEstadoTransferencia;

            Button btnDetenerTransferencia = new Button();
            btnDetenerTransferencia.Size = new Size(30, 30);
            btnDetenerTransferencia.BackgroundImage = Properties.Resources.Eliminar;
            btnDetenerTransferencia.BackgroundImageLayout = ImageLayout.Stretch;
            btnDetenerTransferencia.Location = new Point(450, 25);
            btnDetenerTransferencia.Click += new EventHandler(btnDetenerTransferencia_Click);
            btnDetenerTransferencia.Name = "btn" + _idTransferencia;
            pnlTransferencia.Controls.Add(btnDetenerTransferencia);

            flpTransferencias.Controls.Add(pnlTransferencia);
            tcNodo.SelectedIndex = 1;
            bgwTransferencia.RunWorkerAsync(data);
        }

        private void bgwTransferencia_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bgw = sender as BackgroundWorker;
            TransferenciaItem data = e.Argument as TransferenciaItem;
            e.Result = data;

            AdminNodos admin = new AdminNodos(_servidor);
            string path;
            int idComando = 0;
            ResultadoComando resultado = null;

            if (data.EsSubida)
                admin.SubirArchivo(data.ArchivoLocal, data.PathRemoto);
            else
                idComando = admin.SolicitarAccion(_nodo, TipoComando.Descargar, data.PathRemoto);

            bgw.ReportProgress(30, data.ProgressBar);

            if (bgw.CancellationPending)
                return;

            if (data.EsSubida)
            {
                path = data.PathRemoto + @"\" + ofdSubir.SafeFileName;
                idComando = admin.SolicitarAccion(_nodo, TipoComando.Subir, path);
                bgw.ReportProgress(60, data.ProgressBar);
            }

            do
            {
                resultado = admin.ObtenerResultado(idComando);
                System.Threading.Thread.Sleep(1000);
            } while (!e.Cancel && resultado == null);

            data.Error = resultado.Error;

            if (!data.EsSubida && resultado.Error == null)
            {
                string[] array = data.PathRemoto.Split(new string[] { @"\" }, StringSplitOptions.RemoveEmptyEntries);
                string nombre = array[array.Length - 1];
                admin.DescargarArchivo(nombre, fbdDescargar.SelectedPath);
                bgw.ReportProgress(80, data.ProgressBar);
            }
        }

        private void bgwTransferencia_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ProgressBar pb = e.UserState as ProgressBar;
            pb.Value = e.ProgressPercentage;
        }

        private void bgwTransferencia_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
                return;

            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message, "ERROR al transferir", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            TransferenciaItem data = e.Result as TransferenciaItem;

            if (data != null)
            {
                data.ProgressBar.Value = 100;

                if (data.Error != null && data.Error.Length > 0)
                {
                    data.LblDescripcionTransferencia.Text += " -[ERROR:] " + data.Error;
                    data.LblDescripcionTransferencia.ForeColor = Color.Red;
                }
                else
                    data.LblDescripcionTransferencia.Text += " [Finalizado]";
            }
        }

        private void btnDetenerTransferencia_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            Panel pnl = btn.Parent as Panel;
            FlowLayoutPanel flp = pnl.Parent as FlowLayoutPanel;

            flpTransferencias.Controls.Remove(pnl);

            int idTransferencia = int.Parse(btn.Name.Replace("btn", ""));

            if (_transferencias.ContainsKey(idTransferencia))
            {
                BackgroundWorker bgw = _transferencias[idTransferencia];

                if (bgw.IsBusy)
                    bgw.CancelAsync();
            }
        }

        private void btnDescargar_Click(object sender, EventArgs e)
        {
            if(fbdDescargar.ShowDialog() == DialogResult.OK)
                AgregarTransferencia(false);
        }

        private void btnSubir_Click(object sender, EventArgs e)
        {
            if (ofdSubir.ShowDialog() == DialogResult.OK)
                AgregarTransferencia(true);
        }

        #endregion

        #region Estado

        private void tmrChequearEstado_Tick(object sender, EventArgs e)
        {
            tmrChequearEstado.Stop();
            picEstado.BackgroundImage = Properties.Resources.BuscandoOnline;
            toolTip.SetToolTip(picEstado, "Chequeando...");
            bgwChequearEstado.RunWorkerAsync();
        }

        private void bgwChequearEstado_DoWork(object sender, DoWorkEventArgs e)
        {
            AdminNodos admin = new AdminNodos(_servidor);
            e.Result = admin.NodoEstaOnline(_nodo);
        }

        private void bgwChequearEstado_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
                picEstado.BackgroundImage = Properties.Resources.Offline;
                toolTip.SetToolTip(picEstado, "OFFLINE");
                return;
            }

            bool resultado = false;

            if (e.Result != null)
                resultado = (bool)e.Result;

            if (resultado)
            {
                picEstado.BackgroundImage = Properties.Resources.Online;
                toolTip.SetToolTip(picEstado, "ONLINE");
            }
            else
            {
                picEstado.BackgroundImage = Properties.Resources.Offline;
                toolTip.SetToolTip(picEstado, "OFFLINE");
            }

            tmrChequearEstado.Start();
        }

        #endregion
    }
}
